package student

// 导入必要的包
import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log/slog"
	"net/http"
	"strconv"
	"student_api/internal/storage"
	"student_api/internal/types" // 导入学生数据模型
	"student_api/internal/utils/response"

	"github.com/go-playground/validator/v10"
)

// New 函数创建并返回一个学生相关的 HTTP 请求处理器
// 该函数设计为工厂模式，每次调用都会返回一个新的处理器实例
// 返回值是一个 http.HandlerFunc 类型的函数，符合 HTTP 处理器接口
func New(storage storage.Storage) http.HandlerFunc {
	// 返回一个匿名函数，该函数接收两个参数：
	// - w: http.ResponseWriter 用于写入 HTTP 响应
	// - r: *http.Request 包含客户端请求信息
	return func(w http.ResponseWriter, r *http.Request) {
		student := types.Student{}

		// 从 HTTP 请求体中解码 JSON 数据到 student 结构体
		err := json.NewDecoder(r.Body).Decode(&student)
		// 检查错误是否为文件结束错误（EOF），表示请求体为空
		if errors.Is(err, io.EOF) {
			response.WriteJson(w, http.StatusBadRequest, response.GeneralError(fmt.Errorf("缺少参数")))
			return
		}

		// 检查是否发生错误
		if err != nil {
			// 如果发生错误，向客户端返回400错误状态码和错误信息
			response.WriteJson(w, http.StatusBadRequest, response.GeneralError(err))
			return // 立即返回，终止当前处理流程
		}

		// 使用验证器对 student 结构体进行字段验证
		if err := validator.New().Struct(student); err != nil {
			// 将错误类型断言为验证错误集合（ValidationErrors）
			var validateErrs validator.ValidationErrors
			errors.As(err, &validateErrs)
			// 将验证错误转换为标准响应格式，并返回 400 状态码
			response.WriteJson(w, http.StatusBadRequest, response.ValidationError(validateErrs))
			return
		}

		// 调用存储层创建学生记录，传入学生对象的各个字段
		lastId, err := storage.CreateStudent(
			student.Name,  // 学生姓名
			student.Email, // 学生邮箱
			student.Age,   // 学生年龄
		)

		// 检查学生记录创建是否出错
		if err != nil {
			// 如果创建失败，返回500服务器错误和错误信息
			response.WriteJson(w, http.StatusInternalServerError, err)
			// 终止当前处理流程
			return
		}

		// 记录日志，表明正在处理创建学生的请求
		slog.Info("user created successfully", slog.String("userId", fmt.Sprint(lastId)))

		response.WriteJson(w, http.StatusCreated, map[string]int64{"id": lastId})
	}
}

// GetByID GetById 创建根据ID查询学生的HTTP处理器
func GetByID(storage storage.Storage) http.HandlerFunc {
	// 返回实际的HTTP处理函数
	return func(w http.ResponseWriter, r *http.Request) {
		// 从URL路径参数中获取学生ID
		id := r.PathValue("id")

		// 记录查询日志：操作类型和学生ID
		slog.Info("getting a student", slog.String("id", id))

		// 将字符串类型的ID转换为64位整数
		intId, err := strconv.ParseInt(id, 10, 64)

		// 检查字符串转换是否出错（如ID包含非数字字符）
		if err != nil {
			// 如果转换失败，返回400错误请求状态码和错误信息
			response.WriteJson(w, http.StatusBadRequest, response.GeneralError(err))
			// 终止当前处理流程
			return
		}

		// 调用存储层方法，根据整数ID查询学生信息
		student, _ := storage.GetStudentById(intId)
		// 检查查询学生信息是否出错
		if err != nil {
			// 使用slog记录错误日志：获取用户信息时发生异常
			slog.Error(
				"error getting user",  // 错误消息描述
				slog.String("id", id), // 记录导致错误的用户ID参数
			)
			// 如果查询失败，返回500服务器内部错误状态码和错误信息
			response.WriteJson(w, http.StatusInternalServerError, response.GeneralError(err))
			// 终止当前处理流程
			return
		}

		// 查询成功，返回200状态码和学生信息的JSON响应
		response.WriteJson(w, http.StatusOK, student)
	}
}

// GetList 创建获取学生列表的HTTP处理器
func GetList(storage storage.Storage) http.HandlerFunc {
	// 返回实际的HTTP请求处理函数
	return func(w http.ResponseWriter, r *http.Request) {
		// 记录获取学生列表的操作日志
		slog.Info("getting all students")

		// 调用存储层获取所有学生数据
		students, err := storage.GetStudents()
		// 检查数据获取是否出错
		if err != nil {
			// 如果出错，返回500服务器内部错误和错误信息
			response.WriteJson(w, http.StatusInternalServerError, err)
			// 终止当前处理流程
			return
		}

		// 查询成功，返回200状态码和学生列表数据的JSON响应
		response.WriteJson(w, http.StatusOK, students)
	}
}
